package com.duoec.dw.lineage.core.utils;

import com.duoec.dw.lineage.service.LineageTableService;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;

import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author xuwenzhen
 */
public class ScriptFormatUtils {
    private static final Pattern HIVE_VAR_PATTERN = Pattern.compile("(^|[^'])(\\$\\{.+?})([^']|$)");
    private static final Pattern LIFECYCLE_PATTERN = Pattern.compile("(LIFECYCLE\\s+\\d+)");
    public static final String TURN_LINE = "\n";
    public static final String COMMENT_LINE = "--";
    public static final String SEMICOLON = ";";
    public static final String CREATE_TEMPORARY_MACRO = "create temporary macro";
    public static final String DROP_TEMPORARY_MACRO = "drop temporary macro";
    public static final String STR_REGEXP = "regexp";

    public static <T> T wrap(String script, Function<String, T> supplier) {
        List<String> lines = Lists.newArrayList(Splitter.on(TURN_LINE).split(script).iterator());
        fixRegex(lines);
        fixMacro(lines);
        fixEngine(lines);
        fixLifecycle(lines);
        String sql = Joiner.on(TURN_LINE).join(lines);
        try {
            return supplier.apply(sql);
        } finally {
            LineageTableService.RUNTIME_TABLES.remove();
        }
    }

    private static void fixLifecycle(List<String> lines) {
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            Matcher matcher = LIFECYCLE_PATTERN.matcher(line);
            if (matcher.find()) {
                String newLine = matcher.replaceFirst("-- $1");
                lines.set(i, newLine);
            }
        }
    }

    private static final Pattern REGEXP_VAR = Pattern.compile("\\$\\{(\\w+)}");

    private static void fixRegex(List<String> lines) {
        //and app_name REGEXP '^${wf_id}$' )
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            String lowerLine = line.toLowerCase();
            int index = lowerLine.indexOf(STR_REGEXP);
            if (index == -1) {
                continue;
            }
            //检查是否包含变量
            index = line.indexOf("$", index);
            if (index == -1) {
                continue;
            }
            Matcher matcher = REGEXP_VAR.matcher(line);
            while (matcher.find()) {
                line = matcher.replaceAll("$1");
            }
            lines.set(i, line);
        }
    }

    private static void fixEngine(List<String> lines) {
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            String lowerCaseLine = line.toLowerCase().trim();
            if (lowerCaseLine.startsWith("engine=")) {
                lines.set(i, "--" + line + "\n;");
            }
        }
    }

    private static void fixMacro(List<String> lines) {
        boolean inVarCode = false;
        for (int i = 0; i < lines.size(); i++) {
            replaceHiveVar(lines, i);

            String line = lines.get(i);
            String lowerCaseLine = line.toLowerCase().trim();
            if (
                    lowerCaseLine.startsWith("set ")
                            || lowerCaseLine.startsWith("add ")
                            || lowerCaseLine.startsWith(DROP_TEMPORARY_MACRO)
                            || lowerCaseLine.startsWith(CREATE_TEMPORARY_MACRO)
            ) {
                inVarCode = true;
            }
            if (inVarCode) {
                line = COMMENT_LINE + line;
                if (lowerCaseLine.endsWith(SEMICOLON)) {
                    inVarCode = false;
                }
                lines.set(i, line);
            }
        }
    }

    public static void replaceHiveVar(List<String> lines, int index) {
        String line = lines.get(index);
        int i = line.indexOf("$");
        if (i == -1) {
            return;
        }
        if (line.length() > i + 1 && line.charAt(i + 1) != '{') {
            return;
        }
        StringBuilder sb = new StringBuilder();
        Matcher matcher = HIVE_VAR_PATTERN.matcher(line);
        int lastEndIndex = 0;
        boolean hasMatch = false;
        while (matcher.find()) {
            hasMatch = true;
            int start = matcher.start(2);
            int end = matcher.end(2);

            if (lastEndIndex != start) {
                sb.append(line, lastEndIndex, start);
            }
            sb.append("'").append(matcher.group(2)).append("'");
            lastEndIndex = end;
        }
        if (lastEndIndex < line.length()) {
            sb.append(line.substring(lastEndIndex));
        }
        if (hasMatch) {
            lines.set(index, sb.toString());
        }
    }
}
